package com.whyw.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.whyw.entity.vo.UserWithRole;
import com.whyw.system.dao.UserDao;
import com.whyw.system.mapper.UserMapper;
import com.whyw.system.security.JwtUtil;
import com.whyw.system.utils.UserContextHolder;
import com.whyw.constant.UserConstant;
import com.whyw.entity.User;
import com.whyw.system.service.UserService;
import com.whyw.entity.vo.LoginUser;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 系统用户表(User)表服务实现类
 *
 * @author makejava
 * @since 2025-06-28 18:59:54
 */
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {

    @Value("${jwt.expiration_time}")
    private long expirationTime;

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private UserDao userDao;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private UserMapper userMapper;

    @Override
    public boolean register(User user) {
        User exist = userDao.selectOne(new LambdaQueryWrapper<>(User.class)
                .eq(User::getUsername, user.getUsername())
        );
        if (exist != null) {
            throw new RuntimeException(UserConstant.USERNAME_EXIST);
        }
        return userDao.insert(user) > 0;
    }

    @Override
    public User loadUserByUsername(String username) {
        return userDao.selectOne(new LambdaQueryWrapper<>(User.class).eq(User::getUsername, username));
    }

    @Override
    public String login(LoginUser loginUser) {
        User user = loadUserByUsername(loginUser.getUsername());

        if (user == null || !passwordEncoder.matches(loginUser.getPassword(), user.getPassword())) {
            throw new RuntimeException(UserConstant.LOGIN_FAILED);
        }

        String token = jwtUtil.createJWT(
                Map.of(
                    UserConstant.USERNAME, loginUser.getUsername()
                )
        );

        UserContextHolder.setUser(user);
        stringRedisTemplate.opsForValue().set(UserConstant.USER_TOKEN + user.getUsername(), token,
                expirationTime, TimeUnit.MILLISECONDS);
        user.setLastLogin(new Date());
        updateById(user);
        return token;
    }

    @Override
    public String logout() {

        SecurityContextHolder.clearContext();

        Long userId = UserContextHolder.getUserId();
        UserContextHolder.clear();

        deleteToken(userId);

        return UserConstant.LOGOUT;
    }

    @Override
    public UserWithRole getUserWithRole(Long userId) {
        return userMapper.getRoles(userId);
    }

    @Override
    public void deleteToken(Long userId) {
        stringRedisTemplate.delete(UserConstant.USER_TOKEN + userId);
    }
}

